﻿using LightCAD.Core;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LightCAD.Runtime;
using static LightCAD.Runtime.Constants;
using System.Xml.Linq;
using System.Runtime.CompilerServices;
using LightCAD.Core.Elements;

namespace LightCAD.Drawing
{

    public class BlockAction
    {


        protected CancellationTokenSource cts;
        protected bool isFinish;
        protected DocumentRuntime docRt;
        protected ViewportRuntime vportRt;

        private string blockName;
        private Vector2d basePoint;
        private List<LcElement> selectedElements;


        public BlockAction(DocumentRuntime docRt)
        {
            this.docRt = docRt;
            this.vportRt = docRt.DrawingEditRt.ActiveViewportRt;
        }
        public BlockAction()
        {
        }
        public void Prompt(string prompt)
        {
            this.docRt.CommandCtrl.Prompt(prompt);
        }
        public BlockAction SetViewport(ViewportRuntime vportRt)
        {
            this.vportRt = vportRt;
            return this;
        }

        public async void ExecCreate(string[] args)
        {
            var pointInputer = new PointInputer(this.docRt);
            var elementSetInputer = new ElementSetInputer(this.docRt);

            var win = (IBlockDefWindow)AppRuntime.UISystem.CreateWindow("BlockDefWindow", this);

            if (this.docRt.Action.SelectedElements.Count > 0)
            {
                selectedElements = new List<LcElement>(this.docRt.Action.SelectedElements);
                win.Elements = selectedElements;
            }
        ShowDlg:
            var result = AppRuntime.UISystem.ShowDialog(win);
            if (result == LcDialogResult.OK)
            {
                if (win.CurrentAction == "SelectPoint")
                {
                    var result1 = await pointInputer.Execute("输入插入点：");
                    if (result1.Value != null)
                    {
                        basePoint = (Vector2d)result1.Value;
                        win.BasePoint = basePoint;
                    }
                    goto ShowDlg;
                }
                else if (win.CurrentAction == "SelectObjects")
                {
                    var result2 = await elementSetInputer.Execute("选择元素：");
                    selectedElements = (List<LcElement>)result2.Value;
                    win.Elements = selectedElements;
                    goto ShowDlg;
                }
                else if (win.CurrentAction == "OK")//
                {
                    this.blockName = win.BlockName;
                    this.CreateBlock();
                    this.docRt.Action.CancelAll();
                }
                else if (win.CurrentAction == "Cancel")
                {

                }
            }
        }

        private void CreateBlock()
        {
            DocumentManager.CurrentRecorder.BeginAction("BLOCK");
            var doc = this.docRt.Document;
            var block = doc.CreateObject<LcBlock>();
            block.Name = this.blockName;

            foreach (var element in selectedElements)
            {
                doc.ModelSpace.RemoveElement(element);
                block.InsertElement(element);
            }

            //使用基点，将元素的世界坐标转换为局部坐标
            foreach (var element in selectedElements)
            {
                element.Translate(-basePoint);
            }

            //转换完成后，将基点的局部坐标设置为零零
            block.BasePoint = Vector2d.Zero;
            doc.Blocks.Add(block);//TODO 需要触发事件

            var blockRef = doc.CreateObject<LcBlockRef>(block);
            blockRef.Set(matrix: Matrix3d.Translate(basePoint));
            doc.ModelSpace.InsertElement(blockRef);
            DocumentManager.CurrentRecorder.EndAction();
        }
        /// <summary>
        /// 编辑块，新开一个视口进行编辑
        /// </summary>
        /// <param name="args"></param>
        public void ExecEdit(string[] args)
        {

        }

        /// <summary>
        /// 在位编辑块
        /// </summary>
        /// <param name="args"></param>
        public void ExecRefEdit(string[] args)
        {
            if (this.vportRt.IsRefEditing)
            {
                Prompt("已经处于在位编辑中.");
                return;
            }
            if (this.docRt.Action.SelectedElements.Count > 0)
            {
                if (this.docRt.Action.SelectedElements.Count == 1 &&
                    (this.docRt.Action.SelectedElements[0] is LcBlockRef))
                {
                    StartRefEditing(this.docRt.Action.SelectedElements[0] as LcBlockRef);
                }
                this.docRt.Action.CancelAll();
                return;
            }

            Prompt("请选择块引用元素.");
            return;
        }

        private void StartRefEditing(LcBlockRef blkRef)
        {
            var isEmbedRef = blkRef.Block.Elements.FirstOrDefault(ele => ele.Type == BuiltinElementType.BlockRef) != null;
            if (isEmbedRef)
            {
                var blkRefSelector = AppRuntime.UISystem.CreateWindow("RefEditSelector") as IRefEditSelector;
                blkRefSelector.Source = blkRef;
                if (AppRuntime.UISystem.ShowDialog(blkRefSelector) != LcDialogResult.OK)
                    return ;

                var refObj = new RefEditingObject()
                {
                    RefLinks = blkRefSelector.RefLinks,
                    Target = blkRef,
                };
                refObj.RefMatrixes = refObj.RefLinks.Select(r => r.Matrix).ToArray();
                refObj.Index = Array.IndexOf(refObj.RefLinks, refObj.Target);
                this.vportRt.RefEditingObject = refObj;
            }
            else
            {
               var refObj = new RefEditingObject()
                {
                    RefLinks = new LcBlockRef[] { blkRef },
                    RefMatrixes = new Matrix3d[] { blkRef.Matrix },//此处需要进行嵌套叠加计算
                    Target = blkRef,
                    Index = 0
                };
                this.vportRt.RefEditingObject = refObj;
            }
            this.vportRt.RefEditingObject.Initilize(this.docRt.Document);
            this.vportRt.RefEditingObject.ElementsToWcs();
            this.vportRt.StartRefEditing();
            Prompt("进入在位编辑状态，输入REFCLOSE退出.");
        }

        public void ExecRefClose(string[] args)
        {
            this.vportRt.CloseRefEditing();
            Prompt("退出了在位编辑状态.");

        }
        public void Replace(string[] args)
        {

        }
    }

}
